﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Windows.Data;
using System.Diagnostics;
using System.Windows;

namespace DotNetZen.Presentation.Converters
{
    public abstract class Evaluator
    {
        [DebuggerStepThrough]
        internal object Convert(object[] values, CultureInfo info)
        {
            // Sometimes, we just don't do anything here.
            if (this.Mode == BindingMode.OneWayToSource)
                return Binding.DoNothing;

            if (this.Mode == BindingMode.OneTime &&
                this.lastGoodConversionValue != DependencyProperty.UnsetValue)
            {
                return this.lastGoodConversionValue;
            }

            object value = this.ConvertCore(values,
                (this.converterCulture ?? info));

            if (value != DependencyProperty.UnsetValue)
            {
                if (value != Binding.DoNothing)
                {
                    this.lastGoodConversionValue = value;
                }
                else
                {
                    return this.lastGoodConversionValue;
                }
            }

            return value;
        }

        protected internal abstract object ConvertCore(object[] values, CultureInfo info);

        [DebuggerStepThrough]
        internal void ConvertBack(object value, Type[] targetTypes, CultureInfo info, object[] returnedItems)
        {
            // Sometimes, we just don't do anything here.
            if (this.Mode == BindingMode.OneWay ||
                this.Mode == BindingMode.OneTime)
                return;

            this.ConvertBackCore(value, targetTypes,
                (this.converterCulture ?? info), 
                returnedItems);
        }

        protected internal abstract void ConvertBackCore(object value, Type[] targetTypes, CultureInfo info, object[] returnedItems);

        #region BindingMode Mode { get; set; } (mode)
        private BindingMode mode;

        /// <summary>
        /// Gets or sets the mode of the binding.
        /// </summary>
        [System.ComponentModel.Description("Indicates the mode of the binding.")]
        public BindingMode Mode
        {
            [System.Diagnostics.DebuggerStepThrough]
            get
            {
                return this.mode;
            }
            [System.Diagnostics.DebuggerStepThrough]
            set
            {
                if (this.mode != value)
                {
                    this.mode = value;
                }
            }
        }
        #endregion

        #region object ConverterParameter { get; set; } (converterParameter)
        private object converterParameter;

        /// <summary>
        /// Gets or sets the parameter sent to the converter.
        /// </summary>
        [System.ComponentModel.Description("Indicates the parameter sent to the converter.")]
        public object ConverterParameter
        {
            [System.Diagnostics.DebuggerStepThrough]
            get
            {
                return this.converterParameter;
            }
            [System.Diagnostics.DebuggerStepThrough]
            set
            {
                if (this.converterParameter != value)
                {
                    this.converterParameter = value;
                }
            }
        }
        #endregion

        #region CultureInfo ConverterCulture { get; set; } (converterCulture)
        private CultureInfo converterCulture;

        /// <summary>
        /// Gets or sets the culture sent to the converter.
        /// </summary>
        [System.ComponentModel.Description("Indicates the culture sent to the converter.")]
        public CultureInfo ConverterCulture
        {
            [System.Diagnostics.DebuggerStepThrough]
            get
            {
                return this.converterCulture;
            }
            [System.Diagnostics.DebuggerStepThrough]
            set
            {
                if (this.converterCulture != value)
                {
                    this.converterCulture = value;
                }
            }
        }
        #endregion

        #region object LastGoodConversionValue { get; } (lastGoodConversionValue)
        private object lastGoodConversionValue = DependencyProperty.UnsetValue;

        /// <summary>
        /// Gets the last good conversion value.
        /// </summary>
        [System.ComponentModel.Description("Indicates the last good conversion value.")]
        protected object LastGoodConversionValue
        {
            [System.Diagnostics.DebuggerStepThrough]
            get
            {
                return this.lastGoodConversionValue;
            }
        }
        #endregion
    }
}
